/*
 * Copyright 2023 Huawei Cloud Computing Technology Co., Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.huawei.cloudphoneime;

import static com.huawei.cloudphoneime.CaeImeProtocol.IME_PASTE_FROM_PC_SDK;

import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.content.ClipData;
import android.content.ClipboardManager;
import android.content.Context;
import android.content.Intent;
import android.inputmethodservice.InputMethodService;
import android.os.Build;
import android.view.KeyEvent;
import android.view.inputmethod.ExtractedText;
import android.view.inputmethod.ExtractedTextRequest;
import android.view.inputmethod.InputConnection;

public class CaeImeService extends InputMethodService {
    private static final String TAG = "CloudPhoneIme";
    private static final String IME_CURSOR_SEPARATOR = "=";
    private CaeImeServer mImeServer;
    private CaeImeRequest mImeRequest;
    private Context mContext;

    public CaeImeService() {
        mImeRequest = null;
        mImeServer = CaeImeServer.defaultImeServer();
    }

    @Override
    public void onCreate() {
        super.onCreate();
        mContext = getApplicationContext();
        mImeServer.setRequestListener(new NewRequestListener());
        mImeServer.start();
        CaeImeLog.i(TAG, "Ime service on create.");
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        mImeServer.stop();
        if (mImeRequest != null) {
            mImeRequest.stopProcess();
            mImeRequest = null;
        }
        mContext = null;
        CaeImeLog.i(TAG, "Ime service on destroy.");
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        CaeImeLog.i(TAG, "onStartCommand.");
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            String channel_id = "CaeImeService-id";
            String channel_name = "CaeImeService-name";
            NotificationManager manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
            NotificationChannel channel = new NotificationChannel(channel_id, channel_name, NotificationManager.IMPORTANCE_MIN);
            if (manager != null) {
                manager.createNotificationChannel(channel);
            }
            Notification notification = new Notification.Builder(this).
                    setAutoCancel(true).setChannelId(channel_id).setSmallIcon(R.drawable.icon).build();
            startForeground(100, notification);
        }
        return START_STICKY;
    }

    @Override
    public void showWindow(boolean showInput) {
        super.showWindow(showInput);
        if (mImeRequest != null && mImeRequest.isSupportShowWindow()) {
            InputConnection ic = getCurrentInputConnection();
            if (ic == null) {
                return;
            }
            CaeImeProtocol.IMEShowKeyBoardPkt showKeyBoardPkt = new CaeImeProtocol.IMEShowKeyBoardPkt(null);
            byte[] data = showKeyBoardPkt.get();
            int res = mImeRequest.send(data);
            if (res < 0) {
                CaeImeLog.e(TAG, "Send show keyboard msg failed.");
                return;
            }
        }
    }

    @Override
    public void hideWindow() {
        super.hideWindow();
        if (mImeRequest != null && mImeRequest.isSupportShowWindow()) {
            CaeImeProtocol.IMEHideKeyBoardPkt hideKeyBoardPkt = new CaeImeProtocol.IMEHideKeyBoardPkt();
            byte[] data = hideKeyBoardPkt.get();
            mImeRequest.send(data);
        }
    }

    private String getClipBoardContent() {
        Context context = this.getApplicationContext();
        ClipboardManager cm = (ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE);
        if (cm == null) {
            return null;
        }
        ClipData data = cm.getPrimaryClip();
        if (data == null) {
            return null;
        }
        ClipData.Item item = data.getItemAt(0);
        if (item == null) {
            return null;
        }
        return item.getText().toString();
    }

    class NewRequestListener implements CaeImeRequestListener {
        @Override
        public void onNewRequest(CaeImeRequest caeImeRequest) {
            if (mImeRequest != null) {
                mImeRequest.unregisterClipEvents();
                mImeRequest.stopProcess();
                mImeRequest = null;
            }
            mImeRequest = caeImeRequest;
            mImeRequest.setTextChangeListener(new TextChangeListener());
            mImeRequest.startProcess();
            mImeRequest.setContext(mContext);
            mImeRequest.registerClipEvents();
        }
    }

    class TextChangeListener implements CaeImeEditChangeListener {

        @Override
        public void onRecvText(byte[] data) {
            String text = new String(data);
            commitText(text);
        }

        @Override
        public void onRecvKeyEvent(int keycode) {
            InputConnection ic = getCurrentInputConnection();
            ic.sendKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN, keycode));
        }

        @Override
        public void onRecvPasteEvent(byte[] data, int type) {
            ClipboardManager clipboardManager = (ClipboardManager) mContext.getSystemService(CLIPBOARD_SERVICE);
            String clipboardText = new String(data);
            if (clipboardText.isEmpty()) {
                CaeImeLog.e(TAG, "clipboard text is invalid");
                return;
            }
            CaeImeLog.i(TAG, "set up content to clipboard");
            ClipData clipData = ClipData.newPlainText(null, clipboardText);
            clipboardManager.setPrimaryClip(clipData);

            if (mImeRequest != null && type == IME_PASTE_FROM_PC_SDK) {
                CaeImeProtocol.IMEPasteKeyEventPkt pasteKeyEventPkt = new CaeImeProtocol.IMEPasteKeyEventPkt();
                byte[] pasteKeyEventPktData = pasteKeyEventPkt.get();
                mImeRequest.send(pasteKeyEventPktData);
            }
        }

        private void commitText(String text) {
            InputConnection ic = getCurrentInputConnection();
            if (ic == null || text.isEmpty()) {
                return;
            }
            ic.commitText(text, 1);
        }
    }
}